﻿namespace Gamelight.Graphics
{
	public static class Draw
	{
		private static EllipseDrawer ellipseDrawer = new EllipseDrawer();
		private static LineDrawer lineDrawer = new LineDrawer();
		private static PolygonDrawer polygonDrawer = new PolygonDrawer();
		private static RectangleDrawer rectangleDrawer = new RectangleDrawer();

		public static void CircleAntialias(Image target, Color color, int centerX, int centerY, int radius)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(centerX - radius - 1, centerY - radius - 1, centerX + radius + 1, centerY + radius + 1);
			ellipseDrawer.DrawEllipse(
				surface.Pixels,
				surface.Antialias,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				surface.AntiaAliasCounter,
				centerX, centerY, radius, radius, true);
			surface.BlitOntoImage(target, color);
		}

		public static void EllipseAntialias(Image target, Color color, int centerX, int centerY, int width, int height)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(centerX - width / 2 - 2, centerY - height / 2 - 2, centerX + width / 2 + 2, centerY + height / 2 + 2);

			ellipseDrawer.DrawEllipse(
				surface.Pixels,
				surface.Antialias,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				surface.AntiaAliasCounter,
				centerX, centerY, width / 2.0, height / 2.0, true);
			surface.BlitOntoImage(target, color);
		}

		public static void Circle(Image target, Color color, int centerX, int centerY, int radius)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(centerX - radius - 1, centerY - radius - 1, centerX + radius + 1, centerY + radius + 1);
			ellipseDrawer.DrawEllipse(
				surface.Pixels,
				surface.Antialias,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				surface.AntiaAliasCounter, 
				centerX, centerY, radius, radius, false);
			surface.BlitOntoImage(target, color);
		}

		public static void Ellipse(Image target, Color color, int centerX, int centerY, int width, int height)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(centerX - width / 2 - 2, centerY - height / 2 - 2, centerX + width / 2 + 2, centerY + height / 2 + 2);

			ellipseDrawer.DrawEllipse(
				surface.Pixels,
				surface.Antialias,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				surface.AntiaAliasCounter, centerX, centerY, width / 2.0, height / 2.0, false);
			surface.BlitOntoImage(target, color);
		}
		
		public static void Text(Image target, int x, int y, string text, string fontName, double fontSize, Color color, FontStyle style)
		{
			Image source = Gamelight.Graphics.Text.Create(text, fontName, fontSize, color, style);
			target.Blit(source, x, y);
		}

		public static void PixelLine(Image target, Color color, Point start, Point end)
		{
			PixelLine(target, color, start.X, start.Y, end.X, end.Y);
		}

		private static void DrawLineImpl(Image target, Color color, int startX, int startY, int endX, int endY, int thickness, bool rounded, bool antialias)
		{
			Polygon(
				target,
				color,
				lineDrawer.GeneratePointListForThickFlatLine(startX, startY, endX, endY, thickness, rounded));
		}

		public static void ThickLine(Image target, Color color, Point start, Point end, int thickness)
		{
			DrawLineImpl(target, color, start.X, start.Y, end.X, end.Y, thickness, false, false);
		}

		public static void ThickLine(Image target, Color color, int startX, int startY, int endX, int endY, int thickness)
		{
			DrawLineImpl(target, color, startX, startY, endX, endY, thickness, false, false);
		}

		public static void RoundCappedLine(Image target, Color color, Point start, Point end, int thickness)
		{
			DrawLineImpl(target, color, start.X, start.Y, end.X, end.Y, thickness, true, false);
		}

		public static void RoundCappedLine(Image target, Color color, int startX, int startY, int endX, int endY, int thickness)
		{
			DrawLineImpl(target, color, startX, startY, endX, endY, thickness, true, false);
		}

		/// <summary>
		/// Draws a line with a single-pixel thickness
		/// </summary>
		public static void PixelLine(Image target, Color color, int startX, int startY, int endX, int endY)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(
				startX < endX ? startX : endX,
				startY < endY ? startY : endY,
				startX > endX ? startX : endX,
				startY > endY ? startY : endY);

			Draw.lineDrawer.DrawPixelLine(
				surface.Pixels,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				startX, startY, endX, endY);

			surface.BlitOntoImage(target, color);
		}

		public static void CompoundPolygon(Image target, Color color, params Point[][] multiplePointLists)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(multiplePointLists);
			polygonDrawer.DrawPolygon(
				surface.Pixels,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				multiplePointLists);
			surface.BlitOntoImage(target, color);
		}

		public static void Polygon(Image target, Color color, Point[] points)
		{
			if (points.Length < 3) return;

			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(points);
			polygonDrawer.DrawPolygon(
				surface.Pixels,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				new Point[][] { points });
			surface.BlitOntoImage(target, color);
		}

		public static void Rectangle(Image target, Color color, int x, int y, int width, int height)
		{
			IntermediateSurface surface = IntermediateSurface.InitializeTransaction(x, y, x + width, y + height);
			rectangleDrawer.DrawRectangle(
				surface.Pixels,
				surface.YAffectedAtAll,
				surface.MinYAffected,
				surface.MaxYAffected,
				surface.Counter,
				x, y, width + x - 1, height + y - 1);
			surface.BlitOntoImage(target, color);
		}
	}
}
